package twinb;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import twinb.interest.ContentInterestModel;
import twinb.interest.PersonInterestModel;
import twinb.text.Search;
import winterwell.jtwitter.Twitter;

public class Twinb
{
	static Map<String, Twinb> 	server		= new HashMap<String, Twinb>();
	
    static public int           IncomingTweetPage = 10,
    							CvsPerPage=10;

    public Twitter              host;

    public Person               user;

    public List<Tweet>          tweets    = new ArrayList<Tweet>(),
            					retweets = new ArrayList<Tweet>();
    
    public Map<Integer, Conversation> idCvs=new HashMap<Integer,Conversation>();
    
    public Map<Long, Tweet>     idTweet   = new HashMap<Long, Tweet>();

    public List<Conversation>   cvses     = new ArrayList<Conversation>();

    public Map<Long, Person>    idPerson  = new HashMap<Long, Person>();

    public List<Person>         people    = new ArrayList<Person>();

    public TimeFactor           timeFactor     = new TimeFactor();

    public PersonInterestModel  pim       = new PersonInterestModel();

    public ContentInterestModel cim       = new ContentInterestModel();

    public List<Set<String>>    diction   = new ArrayList<Set<String>>();
    
    public Search search=new Search(cvses);

    public void setTestUser()
    {
        this.setUser("quyin", "quyintpwd");
    }

    public static void main(String[] args)
    {
        Twinb.server.put("Ximing_Chen",new Twinb());
        Twinb test=Twinb.server.get("Ximing_Chen");
        test.setTestUser();
        test.setTweets();
//        test.setPeople();
        test.setCIM();
//        test.setConversations();
        test.rankCVS();
        test.search.query("贪污");
        // test.cvses.get(7).getHotness();

        List<Conversation> page = test.getCvsPage(1);
    }
    
    public int getNumberOfCvsPages()
    {
        int size = cvses.size();
    	int num= size / Twinb.CvsPerPage + ((size%Twinb.CvsPerPage==0)?0:1);
    	return num;
    }
    
    public List<Conversation> getCvsPage(int page)
    {
    	List<Conversation> cvsPage=new ArrayList<Conversation>();
    	int start=page*Twinb.CvsPerPage;
    	for(int i=0;i<Twinb.CvsPerPage && start+i<this.cvses.size();++i)
    		cvsPage.add(this.cvses.get(start+i));
    	return cvsPage;
    }

    public void rankCVS()
    {
        for (int i = 0; i < this.cvses.size(); ++i)
            cvses.get(i).setRankScore();

        Collections.sort(this.cvses);
    }
/*
    public void setPeople()
    {
        for (int i = 0; i < tweets.size(); ++i)
        {
            Person person = new Person(tweets.get(i).getStatus().user);
            tweets.get(i).user = person;
            long personId = person.user.id;
            if (!idPerson.containsKey(personId))
            {
                people.add(person);
                idPerson.put(personId, person);
            }
        }
        for (int i = 0; i < tweets.size(); ++i)
        {
            Tweet tweet = tweets.get(i);
            long pid = tweet.getStatus().getUser().id;
            Long repId = tweet.getStatus().inReplyToStatusId;
            if (pid == this.user.getUser().id && repId != null && idTweet.containsKey(repId))
            {
                Tweet repTweet = idTweet.get(repId);
                Person person = idPerson.get(repTweet.getStatus().user.id);
                person.addRep();
                pim.reply(person.getId());
            }
        }
        
        List<Long> retweetIds = this.host.getRetweetedByMe();
        for (int i = 0; i < retweetIds.size(); ++i)
        {
            Tweet retweet = this.idTweet.get(retweetIds.get(i));
            if (retweet != null)
            {
                retweets.add(retweet);
                long id = retweet.getStatus().user.id;
                pim.retweet(id);
                if (idPerson.containsKey(id))
                    idPerson.get(id).addRtw();
            }
        }
        
        for (int i = 0; i < people.size(); ++i)
            pim.setNFollowers(people.get(i).getId(), people.get(i).getUser().followersCount);
    }
*/    
    
    public void setCIM()
    {
        List<Long> retweetIds = this.host.getRetweetedByMe();
        for (int i = 0; i < retweetIds.size(); ++i)
        {
            Tweet retweet = this.idTweet.get(retweetIds.get(i));
            if (retweet != null)
            {
                this.feedRetweet(retweet);
            }
        }
    }

    public void feedRetweet(Tweet retweet)
    {
        cim.retweet(retweet.getStatus().text);

    }

    public void feedATweet(Tweet tweet)
    {
    	boolean hasFather=false;
        
        this.idTweet.put(tweet.getStatus().id, tweet);
        Twitter.User user = tweet.getStatus().user;
        if(!this.idPerson.containsKey(user.id))
        {
        	Person person = new Person(user);
        	this.people.add(person);
        	this.pim.setNFollowers(user.id, user.followersCount);
        	this.idPerson.put(user.id, person);
        }
        	
        Long repId=tweet.getStatus().inReplyToStatusId;
        if(repId	!=	null)
        {
        	if(user.id==this.user.getUser().id && idTweet.containsKey(repId))
        		this.pim.reply(this.idTweet.get(repId).user.getUser().id);
        	for(int i:	this.idCvs.keySet())
        		if(this.idCvs.get(i).tweetId.contains(repId))
        		{
        			hasFather=true;
        			this.idCvs.get(i).feedTweet(tweet);
        		}
        }
        
        if(!hasFather)
        {
        	this.diction.add(new HashSet<String>());
        	Conversation cvs	=	new Conversation(this,tweet,this.idPerson,this.cvses.size());
        	this.cvses.add(cvs);
        	int back	=	this.cvses.size()-1;
        	cvs.setId(back);
        	this.idCvs.put(back,cvs);
        	if(user.id==this.user.getId())
        		this.cim.retweet(tweet.getStatus().text);
        }

    }

    public void setUser(String name, String password)
    {
        host = new Twitter(name, password);
        host.setSource("twitter.org");
        user = new Person(this.host.show(name));
    }

    public void newStatus(String statusText)
    {
        Twitter.Status status=host.updateStatus(statusText);
        Tweet tweet=new Tweet(this,status);
        this.feedATweet(tweet); 
    }

    public Person getUser()
    {
        return user;
    }

    public void reply(long inReplyToStatusId, String statusText)
    {
        Tweet tweet = idTweet.get(inReplyToStatusId);
        if (tweet == null)
        {
            tweet = new Tweet(this, host.getStatus(inReplyToStatusId));
        }
        host.updateStatus(statusText, tweet.getStatus());
        this.feedATweet(tweet);
    	//host.updateStatus(statusText, inReplyToStatusId);
    }

    public void retweet(long l)
    {
        host.retweet(this.idTweet.get(l).getStatus());
        this.cim.retweet(this.idTweet.get(l).getStatus().text);
    }

    public List<Conversation> getConversations()
    {
        return this.cvses;
    }
/*
    public void setConversations()
    {
        List<List<Tweet>> cvsList = new ArrayList<List<Tweet>>();
        Set<Long> idSet = new HashSet<Long>();
        List<Set<Long>> cvsIdSet = new ArrayList<Set<Long>>();
        Tweet tweet = null;
        Long replyId = null;
        long id = 0;
        int i = 0;
        for (i = tweets.size() - 1; i >= 0; --i)
        {
            tweet = tweets.get(i);
            id = tweet.getStatus().id;
            replyId = tweet.getStatus().inReplyToStatusId;
            if (replyId == null || (!idSet.contains(replyId)))
            {
                idSet.add(id);
                cvsList.add(new ArrayList<Tweet>());
                cvsIdSet.add(new HashSet<Long>());
                int back = cvsList.size() - 1;
                cvsList.get(back).add(tweet);

                back = cvsIdSet.size() - 1;
                cvsIdSet.get(back).add(id);
            }
            else
            {
            	tweet.inReplyToTid=replyId.toString();
            	tweet.inReplyToUid=this.idTweet.get(replyId).user.id;
            	tweet.inReplyToUname=idTweet.get(replyId).user.name;
                for (int j = 0; j < cvsIdSet.size(); ++j)
                    if (cvsIdSet.get(j).contains(replyId))
                    {
                        cvsList.get(j).add(tweet);
                        cvsIdSet.get(j).add(id);
                    }
            }
        }

        for (i = 0; i < cvsList.size(); ++i)
        {
            this.cvses
                    .add(new Conversation(this, cvsList.get(i), idPerson, user.getUser().getId()));
            int back = cvses.size() - 1;
            cvses.get(back).setId(back);
            //Temporary way to set up diction
            cvses.get(back).setKgrams();
            diction.add(new HashSet<String>() );
            for(int j=0;j<cvses.get(i).kgrams.size();++j)
            {
            	String word=cvses.get(i).kgrams.get(j);
            	diction.get(i).add(word);
            }
            	
        }
    }
*/
    public void setTweets()
    {
        int j = 0;

        while (true)
        {
            System.out.println("Page " + j);
            host.setPageNumber(j++);
            List<Twitter.Status> statuslist = host.getHomeTimeline();

            if (j == IncomingTweetPage)
                break;
            if (statuslist.size() == 0)
                break;

            for (int i = 0; i < statuslist.size(); ++i)
            {
                System.out.println(statuslist.get(i));
                Tweet tweet = new Tweet(this, statuslist.get(i));
                this.tweets.add(tweet);
                //this.feedATweet(tweet);
                this.idTweet.put(tweet.getStatus().id, tweet);
            }

        }
        for(int i=this.tweets.size()-1;i>=0;--i)
        	this.feedATweet(this.tweets.get(i));
        
        timeFactor.update(this.tweets.get(0).getTime());
    }

    public List<Tweet> getTweets()
    {
        return this.tweets;
    }

    public List<Person> getFollowing()
    {
        // TODO Auto-generated method stub
        return null;
    }

    private Twinb()
    {
    }

    private static Map<String, Twinb> theMap = new HashMap<String, Twinb>();

    public static Twinb get(String uname)
    {
        if (!theMap.containsKey(uname))
            theMap.put(uname, new Twinb());
        return theMap.get(uname);
    }

    public static void decayAll()
    {
        for (String uname : theMap.keySet())
        {
            theMap.get(uname).pim.decay();
            theMap.get(uname).cim.decay();
        }
    }

    public static void logout(String uname)
    {
        if (theMap.containsKey(uname))
            theMap.remove(uname);
    }
}
